#ifndef SETTINGSMANAGER_H
#define SETTINGSMANAGER_H

#include <string>
#include <sstream>
#include <fstream>
#include <vector>
#include <cstring>

#include "rapidxml.hpp"
#include "rapidxml_print.hpp"

#define SETTINGS_MANAGER_PATH_DELIMITER '/'

using namespace std;
using namespace rapidxml;

/**
 * SettingsManager tries to handle XML Files for String-Settings easily.
 * You can save and read Settings by simply giving it a 'path' to the string you want to read.
 *
 * The paths are simply mapped to the XML-File by attaching every node in the path to a node
 * in the XML file. The root-node is DEFAULT_ROOT_NODE by default. The last node is the attribute.
 *
 * f.e.: 'Debug/PrintError' is translated to: <settings><Debug PrintError=""/></settings>
 */
class SettingsManager
{
    public:
        /**
         * Attempts to read SettingsFile and parse it. In case of error flags are set appropriately.
         * If autosave is set to true the file will be saved on destruction.
         */
        SettingsManager(string SettingsFile, string rootname = "settings", bool autosave = false);

        /**
         * Attempts to read SettingsFile and parse it from given istream. In case of error flags are set appropriately.
         * Autosave is not possible.
         */
        SettingsManager(istream &in, string rootname = "settings");

        /**
         * Get a setting from settingsfile. If the setting was not present it will be created and set to "".
         */
        string getSetting(string name);

        /**
         * Set a setting. If the setting was not present it will be created and set to val. The old value will be returned.
         */
        string setSetting(string name, string val);

        /**
         * Save the settings to file set in constructor.
         */
        bool save();

        /**
         * Save the settings to the given stream.
         */
        bool save(ostream& out);

        /**
         * Return ifstream::good() for input file.
         */
        inline bool isFileGood() { return m_file_good; }
        /**
         * Return flag that is set to false in case of parse errors.
         */
        inline bool isDocumentGood() { return m_doc_good; }
        /**
         * Return isFileGood() && isDocumentGood().
         */
        inline bool isGood() { return m_file_good && m_doc_good; }

		/**
         * Get first node. Creates settings-node if none is present.
         */
        xml_node<>* getFirstNode();

        /**
         * In case of autosave is set to true save() is called on destruction.
         */
        ~SettingsManager();
    protected:
    private:
        /**
         * Name of the root node.
         */
        string m_rootname;
        /**
         * Attempts to parse the given stream. Used by constructor.
         */
        void parseStream(istream& in);

        /**
         * RapidXML document object.
         */
        xml_document<> m_doc;

        /**
         * Buffer for RapidXML.
         */
        char* m_doc_str;

        /**
         * The desired filename. Set in constructor.
         */
        string m_fileName;

        /**
         * Indicates if the document should be saved on destruction. Set in constructor.
         */
        bool m_autoSave;

        /**
         * Indicates if the file was read properly.
         */
        bool m_file_good;

        /**
         * Indicates if the doc was parsed properly.
         */
        bool m_doc_good;

        /**
         * Get attribute, create if not existent.
         */
        xml_attribute<>* getAttrib(vector<string> nodeNames);

        /**
         * Transform a given path to a vector of strings by splitting at '/'.
         */
        vector<string> pathToList(string path);
};

#endif // SETTINGSMANAGER_H